Skip to main content

FHIR Servers

Existing FHIR servers

The platform requires at least one FHIR endpoint to handle it native FHIR resources. If you aleary have this, ensure all the platform components point to said endpoint, you may then skip deployment of default FHIR servers.

By default the platform runs two independent HAPI FHIR server instances, each with its own dedicated Helm chart:

InstanceModule keyFHIR versionContext pathPurpose
ePIfhirEpiR5/epi/apiStores electronic Product Information (ePI) FHIR resources
IPSfhirIpsR4 + IPS/ips/apiStores International Patient Summary (IPS) resources
Why 2?

Because at the time of development the official IPS was not yet specified for FHIR R5, and official ePI IG was developed for R5.

To solve this discrepancy, it was decided to deploy one R4 server for IPS, and a R5 for ePIs (and everythign else).

As consequence, the platform natively distiguishes between patient related information sources (a.k.a IPS), and non-personal resources (i.e. ePIs, and other information like Health Education Material metadata)

Both are deployed via the hapi-fhir-deployments repository and published to GHCR as OCI charts:

  • oci://ghcr.io/gravitate-health/charts/fhir-epi
  • oci://ghcr.io/gravitate-health/charts/fhir-ips

What each chart bundles

Each chart is self-contained:

  • HAPI FHIR JPA Server — official upstream chart, no custom Docker image
  • PostgreSQL — Bitnami chart, bundled as a sub-chart with its own PVC
  • Istio VirtualService — routes /epi/api or /ips/api through the platform gateway
  • Probe-patch Job — post-install/upgrade hook that corrects liveness/readiness/startup probe paths to the server's context path (upstream HAPI hardcodes /livez//readyz)
  • Auto-generated DB credentials Secret — generated on first install, preserved across upgrades, retained after uninstall

Credential management

DB credentials are managed automatically by the chart using Helm's lookup function — no manual secret creation is required.

EventBehaviour
First installGenerates a random 32-character password; creates the Secret
UpgradeLooks up the existing Secret and reuses the same password (idempotent)
helm uninstallSecret is kept (helm.sh/resource-policy: keep) — PVC data stays accessible

When deployed via the helm-charts Helmfile orchestrator, the secrets are named after the release:

  • fhir-server-epi-postgresql (for the fhir-server-epi release)
  • fhir-server-ips-postgresql (for the fhir-server-ips release)

To bring your own credentials instead:

kubectl create secret generic fhir-server-epi-postgresql \
--from-literal=postgres-password=<admin-pw> \
--from-literal=password=<app-pw>

Then set postgresql.auth.existingSecret=fhir-server-epi-postgresql in your values overlay — the chart will use the existing secret and skip generation.

Deployment via Helmfile (standard)

When deploying the full platform with helm-charts, both FHIR servers are included in the phase=data step and enabled by default in all profiles. No extra configuration is required beyond the standard global.host and global.gatewayName.

# Deploy only the data phase (both FHIR servers)
helmfile -f helmfile.yaml -e full -l phase=data apply

Values overlays in helm-charts/values/releases/ wire the gateway name and DB secret names automatically.

Standalone deployment

You can also deploy either chart independently from the hapi-fhir-deployments repository:

git clone https://github.com/Gravitate-Health/hapi-fhir-deployments.git
cd hapi-fhir-deployments

# Update sub-chart dependencies
helm dependency update charts/fhir-epi
helm dependency update charts/fhir-ips

# Deploy (credentials auto-generated)
helm install fhir-epi charts/fhir-epi
helm install fhir-ips charts/fhir-ips
Release name matters

The PostgreSQL service hostname is derived from the Helm release name. The chart default assumes the release is named fhir-epi or fhir-ips. If you use a different release name, override:

helm install my-release charts/fhir-epi \
--set hapi.externalDatabase.host=my-release-postgresql \
--set postgresql.auth.existingSecret=my-release-postgresql

When deployed via helm-charts Helmfile, the release names are fhir-server-epi and fhir-server-ips — the value overlays handle this automatically.

Probe patching — why it exists

The upstream HAPI FHIR Helm chart hardcodes probe paths to /livez and /readyz. When a server runs at a context path (e.g. /epi/api), the actual health endpoints are /epi/api/livez and /epi/api/readyz. Without correction the pod cycles NotReady indefinitely.

Both charts include a Helm hook Job (post-install, post-upgrade) that patches the Deployment probes via kubectl patch immediately after each deploy. The hook runs automatically — no manual action required.

In-cluster service URLs

All platform modules that talk to the FHIR servers use these canonical in-cluster URLs. They are the default values for the FHIR_EPI_URL / FHIR_IPS_URL environment variables across all charts:

VariableDefault value
FHIR_EPI_URLhttp://fhir-server-epi:8080/epi/api/fhir
FHIR_IPS_URLhttp://fhir-server-ips:8080/ips/api/fhir

These values are stable because both charts set hapi.fullnameOverride to fhir-server-epi / fhir-server-ips, pinning the Kubernetes Service name regardless of the Helm release name.

If you point the platform at an external FHIR endpoint, override these variables in each consuming chart. In the helm-charts helmfile you can do this globally via --state-values-set or per-module in values/releases/<module>.yaml.gotmpl:

# Example: values/releases/focusing-manager.yaml.gotmpl
config:
fhirEpiUrl: "https://my-external-fhir.example.org/epi/api/fhir"
fhirIpsUrl: "https://my-external-fhir.example.org/ips/api/fhir"

Accessing the servers

After deployment, the FHIR servers are reachable at:

EndpointePIIPS
FHIR APIhttps://<host>/epi/api/fhir/https://<host>/ips/api/fhir/
Readinesshttps://<host>/epi/api/readyzhttps://<host>/ips/api/readyz
Livenesshttps://<host>/epi/api/livezhttps://<host>/ips/api/livez
IPS summaryhttps://<host>/ips/api/fhir/Patient/<id>/$summary
Prometheus (internal)http://fhir-server-epi:8080/actuator/prometheushttp://fhir-server-ips:8080/actuator/prometheus

Key configuration values

All values are namespaced under hapi.* (upstream sub-chart) or chart-level keys:

ValueePI defaultIPS defaultDescription
hapi.image.tagv7.6.0v7.4.0HAPI FHIR Docker image version
hapi.replicaCount11Number of replicas
virtualService.gatewaygh-gatewaygh-gatewayIstio Gateway resource name
virtualService.uriPrefix/epi/api/ips/apiRouted URI prefix
postgresql.auth.existingSecretfhir-epi-postgresqlfhir-ips-postgresqlDB credentials Secret (auto-created)
postgresql.primary.persistence.size8Gi8GiDB volume size
probePatch.enabledtruetrueRun probe-patch Job on install/upgrade

Full configuration reference: hapi-fhir-deployments README.